package com.dh.blog.service.impl;


import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import javax.annotation.Resource;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.dh.blog.dao.ArticleDao;
import com.dh.blog.dao.ClassifyDao;
import com.dh.blog.dao.CommentDao;
import com.dh.blog.handler.ArticalHandler;
import com.dh.blog.handler.SaveFileHandler;
import com.dh.blog.handler.xml.Catalog;
import com.dh.blog.handler.xml.XmlNode;
import com.dh.blog.service.ArticleService;
import com.dh.blog.vo.ArticlePagerVo;
import com.dh.blog.vo.ArticleVo;
import com.dh.blog.vo.CatalogVo;
import com.dh.blog.vo.CommentRowVo;
import com.dh.blog.vo.CommentVo;
import com.dh.blog.vo.HolderVo;
import com.dh.blog.vo.PagerVo;
import com.dh.blog.vo.PictureFileVo;
import com.ewei.web.common.exception.MessageRuntimeException;
import com.ewei.web.common.utils.FileToolsBar;

@Service("articleService")
@Transactional(readOnly=true)
public class ArticleServiceImpl implements ArticleService {
	private static final boolean IS_ANCHOR = false;
	private static final String TITLE_TAG = "h";
	@Resource
	protected ArticleDao articleDao;
	@Resource
	protected CommentDao commentDao;
	@Resource
	protected Properties config;
	@Resource
	protected ClassifyDao classifyDao;
	@Resource
	protected ArticalHandler articleHandler;
	@Resource
	protected SaveFileHandler saveFile;
	@Override
	@Transactional(readOnly=false)
	public void doCreateArticle(ArticleVo article) {
		if(null != article.getBlog() && !
				StringUtils.isEmpty(article.getBlog().getId())){//这里防止controller没有检验
			Calendar calendar = Calendar.getInstance(); 
			article.setCreateTime(calendar.getTime());
			article.setUpdateTime(System.currentTimeMillis());
			articleDao.addOne(article);
		}else{
			throw new MessageRuntimeException();
		}
	}
	protected Integer doSaveAndIncHolder(String blogId,Integer year,Integer month){
		HolderVo holder = articleDao.getHolderByYearAndMonth(
				blogId,year, month);
		if(null == holder){
			holder = new HolderVo(year,month,blogId);
			articleDao.addHolder(holder);
		}else{
			articleDao.incArticleNum(holder.getId());//入档数increase
		}
		return holder.getId();
	}
	protected void doDecHolder(String blogId,Integer year,Integer month){
		HolderVo holder = articleDao.getHolderByYearAndMonth(
				blogId, year, month);
		if(null == holder){
			throw new MessageRuntimeException("can't not find the holder,maybe the data has been lost");
		}
		articleDao.decArticleNum(holder.getId());
	}
	@Override
	@Transactional(readOnly = false)
	public boolean doPublish(ArticleVo article) {
		String diskPath = article.getDiskpath();
		if(null != diskPath){
			String root = config.getProperty("file_disk_dir");
			diskPath = ((null == root||"".equals(root))?"":root) + diskPath;
			FileInputStream in = null;
			try {
				in = new FileInputStream(diskPath);
			} catch (FileNotFoundException e) {
				throw new MessageRuntimeException(e);
			}
			Document doc = articleHandler.resolveToDocument(in);
			if(IS_ANCHOR){//设置锚点,并存储xml文件
				articleHandler.anchor(doc, TITLE_TAG);
				articleHandler.saveAndUpdate(doc, diskPath);
			}
			Catalog<XmlNode> catalog = articleHandler.createCatalog(doc, IS_ANCHOR);
			Calendar cal = Calendar.getInstance();
			Date time = cal.getTime();
			try {
				ByteArrayInputStream byteIn = new ByteArrayInputStream
								(catalog.serialize().getBytes("UTF-8"));
				CatalogVo catalogVo = articleDao.getCatalogByArticle(article.getId());
				if(null != catalogVo){//若是已经存在目录(多次发布),则不重新插入
					saveFile.saveByRelative(byteIn,catalogVo.getDiskPath());
				}else{
					String catalogPath = saveFile.
							saveByDate(byteIn,time);//不分类存储目录文件
					catalogVo = new CatalogVo(article.getId(),catalogPath); 
					articleDao.addCatalog(catalogVo);//存储目录信息
				}
				doCmprAndSavePic(doc,root,article.getId());//1.compress the imgs in the document;2.save on the disk(if already exited,delete first)
				long updateTime = article.getUpdateTime();
				article.setUpdateTime(time.getTime());
				articleDao.updateOne(article,updateTime);//更新文章信息
				doSaveAndIncHolder(article.getBlog().getId(),
						cal.get(Calendar.YEAR),cal.get(Calendar.MONTH));//文章入档
				//增加类别数量,用于显示
				classifyDao.incNum(article.getClassify().getId());
				return true;
			} catch (UnsupportedEncodingException e) {
				throw new MessageRuntimeException(e);
			}
		}
		return false;
	}
	@Transactional(readOnly=false)
	public boolean doCancelPublish(ArticleVo article){
		Integer id = article.getId();
		List<PictureFileVo> pics = articleDao.getPicsByArticle(id);
		//TODO 删除文件的时候不能回滚，有待解决
		for(int i = 0;i < pics.size();i++){
			PictureFileVo pic = pics.get(i);
			saveFile.remove(pic.getPathCmpr());
		}
		articleDao.deletePics(id);
		long updateTime = article.getUpdateTime();
		article.setUpdateTime(Calendar.
				getInstance().getTimeInMillis());
		articleDao.updateOne(article, updateTime);
		Calendar cal = Calendar.getInstance();
		cal.setTime(article.getReleaseTime());
		doDecHolder(article.getBlog().getId(),
				cal.get(Calendar.YEAR),cal.get(Calendar.MONTH));//删除归档
		classifyDao.decNum(article.getClassify().getId());//减少分类数量，用于显示
		return true;
	}
	@Override
	public ArticleVo getArticleById(Integer articleId) {
		return articleDao.getArticleById(articleId);
	}
	
	@Override
	public List<ArticleVo> getCommandsByBlog(String blogId) {
		return articleDao.getCommandsByBlog(blogId);
	}
	@Override
	public PagerVo getPagerByBlogAndQuery(ArticlePagerVo pager) {
		return articleDao.findPagerByBlog(pager);
	}
	@Override
	public int countByBlogAndQuery(String blogId, Integer classifyId) {
		return articleDao.countByBlogAndCly(blogId, classifyId);
	}
	@Override
	public List<PictureFileVo> getPicsByArticle(Integer articleId) {
		return articleDao.getPicsByArticle(articleId);
	}
	@Override
	@Transactional(readOnly=false)
	public void doComment(CommentVo comment) {
		commentDao.addOne(comment);
	}
	@Override
	public int existsArticle(Integer articleId) {
		return articleDao.exists(articleId);
	}
	@Override
	public int existsComment(String commentId) {
		return commentDao.exists(commentId);
	}
	@Override
	@Transactional(readOnly=false)
	public List<CommentRowVo> getCommentsByArticle(Integer articleId) {
		return commentDao.getCommentsByArticle(articleId);
	}
	@Override
	@Transactional(readOnly=false)
	public int doUpdateArticle(ArticleVo articleVo,long updateTime) {
		return articleDao.updateOne(articleVo,
				updateTime);
	}
	@Override
	public CatalogVo getCatalogByArticle(Integer articleId) {
		return articleDao.getCatalogByArticle(articleId);
	}
	@Override
	public CommentVo getCommentById(String commentId) {
		return commentDao.getCommentById(commentId);
	}
	@Override
	public int countByBlog(String blogId) {
		return articleDao.countByBlog(blogId);
	}
	@Override
	public PagerVo getPagerByBlogAndQueryAdmin(ArticlePagerVo pager) {
		return articleDao.findPagerByBlogAdmin(pager);
	}
	private void doCmprAndSavePic(Document doc,String root,Integer articleId){
		String[] urls = articleHandler.resolveToImgURLs(doc);
		String matDir = config.getProperty("mat_dir");
		String matCmprDir = config.getProperty("cmpr_dir");
		int width = Integer.valueOf(config.getProperty("cmpr_width"));
		int height = Integer.valueOf(config.getProperty("cmpr_height"));
		for(int i = 0;i<urls.length;i++){
			String url = urls[i];
			System.out.println("compressing...."+url);
			int idx = 0;
			if((idx =url.indexOf(matDir)) != -1){
				url = url.substring(idx);
				File f = new File(root+url);
				if(f.exists()){
					String cmpr = saveFile.saveByDir(null, matCmprDir);
					FileToolsBar.compressPic(f, root+cmpr, width, height, true);
					PictureFileVo pic = new PictureFileVo(articleId,url,cmpr);
					articleDao.addPic(pic);
				}
			}
		}
	}
}
